/********************************************************************
	created:	2008/10/01
	created:	1:10:2008   13:32
	filename: 	h:\SimoneEngine\qianye\src\qylib\math\qyVector3.h
	author:		Xiong Jiayu
	copyright:  
	purpose:	
*********************************************************************/
#pragma  once

#ifndef __QYVECTOR3_H__
#define __QYVECTOR3_H__

#include "../common/qyCommon.h"
#include "qyMath.h"

/*
==================================================================
struct Vector3
==================================================================
*/
struct Vector3
{
public:
	float				x;
	float				y;
	float				z;

						Vector3();
						Vector3( const float x, const float y, const float z );
						Vector3( const Vector3 & rhs );

	void				Set( const float x, const float y, const float z );
	void				Zero();

	float				operator []( const int index ) const;
	float &				operator []( const int index );
	Vector3				operator -() const;
	Vector3 &			operator =( const Vector3 &a ) ;

	float				operator *( const Vector3 &a ) const;
	Vector3				operator *( const float a ) const;
	Vector3				operator /( const float a ) const;
	Vector3				operator +( const Vector3 &a ) const;
	Vector3				operator -( const Vector3 &a ) const;

	Vector3 &			operator +=( const Vector3 &a );
	Vector3 &			operator -=( const Vector3 &a );
	Vector3 &			operator *=( const Vector3 &a );
	Vector3 &			operator *=( const float a );
	Vector3 &			operator /=( const Vector3 &a );
	Vector3 &			operator /=( const float a );
	friend Vector3		operator *( const float a, const Vector3 &b );

	bool				Compare( const Vector3 &a ) const;
	bool				Compare( const Vector3 &a, const float epsilon ) const;
	bool				operator ==( const Vector3 &a ) const;
	bool				operator !=( const Vector3 &a ) const;

	Vector3 			Cross( const Vector3 &a ) const;
	Vector3	&			Cross( const Vector3 &a, const Vector3 &b );
	Vector3 			Scale( const Vector3 &a ) const;
	void				ScaleSelf( const Vector3 &a );
	Vector3	&			Scale( const Vector3 &a, const Vector3 &b );
	float				Length() const;
	float				LengthFast() const;
	float				LengthSq() const;
	float				Normalize();		// return length
	float				NormalizeFast();

	int					GetLargestAxis() const;

	int					GetMaximumExtent() const;
};

//-----------------------------------------------------------------------
QY_INLINE Vector3::Vector3()
: x( 0.0f )
, y( 0.0f )
, z( 0.0f )
{
}

//-----------------------------------------------------------------------
QY_INLINE Vector3::Vector3( const Vector3 &rhs )
{
	this->x = rhs.x;
	this->y = rhs.y;
	this->z = rhs.z;
}

//-----------------------------------------------------------------------
QY_INLINE Vector3::Vector3( const float xVal, const float yVal, const float zVal )
{
	this->x = xVal;
	this->y = yVal;
	this->z = zVal;
}

//-----------------------------------------------------------------------
QY_INLINE void Vector3::Set( const float xVal, const float yVal, const float zVal )
{
	this->x = xVal;
	this->y = yVal;
	this->z = zVal;
}

//-----------------------------------------------------------------------
QY_INLINE void Vector3::Zero()
{
	this->x = 0.0f;
	this->y = 0.0f;
	this->z = 0.0f;
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 Vector3::operator -() const
{
	return Vector3( -x, -y, -z );
}

//-----------------------------------------------------------------------
QY_INLINE float Vector3::operator []( const int index ) const
{
	return ( &x )[ index ];
}

//-----------------------------------------------------------------------
QY_INLINE float & Vector3::operator []( const int index )
{
	return ( &x )[ index ];
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 & Vector3::operator =( const Vector3 &a )
{
	this->x = a.x;
	this->y = a.y;
	this->z = a.z;
	return ( *this );
}

//-----------------------------------------------------------------------
QY_INLINE float Vector3::operator *( const Vector3 &a ) const
{
	return x * a.x + y * a.y + z * a.z;
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 Vector3::operator *( const float a ) const
{
	return Vector3( a * x, a * y, a * z );
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 Vector3::operator /( const float a ) const
{
	float inval = 1.0f / a;
	return Vector3( x * inval, y * inval, z * inval );
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 Vector3::operator -( const Vector3 &a ) const
{
	return Vector3( x - a.x, y - a.y, z - a.z );
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 Vector3::operator +( const Vector3 &a ) const
{
	return Vector3( x + a.x, y + a.y, z + a.z );
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 & Vector3::operator +=( const Vector3 &a )
{
	x += a.x;
	y += a.y;
	z += a.z;
	return ( *this );
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 & Vector3::operator -=( const Vector3 &a )
{
	x -= a.x;
	y -= a.y;
	z -= a.z;
	return ( *this );
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 & Vector3::operator *=( const Vector3 &a )
{
	x *= a.x;
	y *= a.y;
	z *= a.z;
	return ( *this );
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 & Vector3::operator *=(const float a)
{
	x *= a;
	y *= a;
	z *= a;
	return ( *this );
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 & Vector3::operator /=(const float a)
{
	float inval = 1.0f / a;
	x *= inval;
	y *= inval;
	z *= inval;
	return ( *this );
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 & Vector3::operator /=(const Vector3 &a)
{
	x /= a.x;
	y /= a.y;
	z /= a.z;
	return ( *this );
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 operator *( const float a, const Vector3 &b )
{
	return Vector3( b.x * a, b.y * a, b.z * a );
}

//-----------------------------------------------------------------------
QY_INLINE bool Vector3::Compare( const Vector3 &a ) const
{
	return ( ( x == a.x ) && ( y == a.y ) && ( z == a.z ) );
}

//-----------------------------------------------------------------------
QY_INLINE bool Vector3::Compare( const Vector3 &a, const float epsilon ) const
{
	if ( fabs( x - a.x ) > epsilon )
		return false;

	if ( fabs( y - a.y ) > epsilon )
		return false;

	if ( fabs( z - a.z ) > epsilon )
		return false;

	return true;
}

//-----------------------------------------------------------------------
QY_INLINE bool Vector3::operator ==( const Vector3 &a ) const
{
	return Compare( a );
}

//-----------------------------------------------------------------------
QY_INLINE bool Vector3::operator !=( const Vector3 &a ) const
{
	return !Compare( a );
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 Vector3::Cross( const Vector3 &a ) const
{
	return Vector3( y * a.z - z * a.y, z * a.x - x * a.z, x * a.y - y * a.x );
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 &Vector3::Cross(const Vector3 &V1, const Vector3 &V2)
{
	/*x = a.y * b.z - a.z * b.y;
	y = a.z * b.x - a.x * b.z;
	z = a.x * b.y - a.y * b.x;*/
    x = V1.y * V2.z - V1.z * V2.y;
    y = V1.z * V2.x - V1.x * V2.z;
    z = V1.x * V2.y - V1.y * V2.x;

	return (*this);
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 Vector3::Scale( const Vector3 &a ) const
{
	return Vector3( x * a.x, y * a.y, z * a.z );
}

//-----------------------------------------------------------------------
QY_INLINE void Vector3::ScaleSelf( const Vector3 &a )
{
	x *= a.x;
	y *= a.y;
	z *= a.z;
}

//-----------------------------------------------------------------------
QY_INLINE Vector3 & Vector3::Scale( const Vector3 &a, const Vector3 &b )
{
	x = a.x * b.x;
	y = a.y * b.y;
	z = a.z * b.z;
	return (*this);
}


//-----------------------------------------------------------------------
QY_INLINE float Vector3::Length() const
{
	return sqrtf( x*x + y*y + z*z );
}

//-----------------------------------------------------------------------
QY_INLINE float Vector3::LengthSq() const
{
	return x * x + y * y + z * z;
}

//-----------------------------------------------------------------------
QY_INLINE float Vector3::Normalize()
{
	float sqrLength, invLength;

	sqrLength = x * x + y * y + z * z;

	if ( !sqrLength ) {		
		return 0.0f;
	}

	invLength = 1.0f / ( sqrtf( sqrLength ) );
	x *= invLength;
	y *= invLength;
	z *= invLength;
	return invLength * sqrLength;
}

//-----------------------------------------------------------------------
QY_INLINE float Vector3::LengthFast() const
{
	const float sqrLength = x * x + y * y + z * z;
	const float temp = sqrLength * qyRSqrt( sqrLength );
	return temp;
}

//-----------------------------------------------------------------------
QY_INLINE float Vector3::NormalizeFast()
{
	float sqrLength, invLength;

	sqrLength = x * x + y * y + z * z;

	if ( !sqrLength ) {		
		return 0.0f;
	}

	invLength = qyRSqrt( sqrLength );
	x *= invLength;
	y *= invLength;
	z *= invLength;
	return invLength * sqrLength;
}

//-----------------------------------------------------------------------
QY_INLINE int Vector3::GetLargestAxis() const
{
	float ax = fabs(x);
	float ay = fabs(y);
	float az = fabs(z);

	if( ax >= ay && ax >= az )
	{	
		return 0;
	}

	if( ay >= ax && ay >= az )
	{
		return 1;
	}
	return 2;
}

//-----------------------------------------------------------------------
QY_INLINE int Vector3::GetMaximumExtent() const
{
	if( x > y && x > z )
		return 0;
	else if( y > z )
		return 1;
	else
		return 2;
}

/*
===========================================
Vector3 const 
===========================================
*/
static const Vector3 Vec3_Orig = Vector3( 0, 0, 0 );
static const Vector3 Vec3_One = Vector3( 1, 1, 1 );
static const Vector3 Vec3_OneX = Vector3( 1, 0, 0 );
static const Vector3 Vec3_OneY = Vector3( 0, 1, 0 );
static const Vector3 Vec3_OneZ = Vector3( 0, 0, 1 );
#endif
